vlwkaos' digital garden

Rust - move_semantics

fn main() {
    let vec0 = Vec::new();

    let mut vec1 = fill_vec(vec0);

    println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);

    vec1.push(88);

    println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}

fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
    let mut vec = vec;

    vec.push(22);
    vec.push(44);
    vec.push(66);

    vec
}
  • fill_vec 내부에서 shadowing을 이용해 새로운 변수를 반환했지만 vec1mut선언 하지않으면 에러가 난다.

Ownership

  • Rust에서 모든 값은 owner 변수를 가진다.
  • 값에 대한 owner는 하나만 존재할 수 있다.
  • owner가 스코프 밖으로 갈 경우 값은 사라진다.
    let s1 = String::from("hello");
    let s2 = s1;

  • Heap에 실제 값을 저장한다. (오른쪽 테이블)
  • Stack에는 Heap을 참조하는 포인터, 배열의 최대 크기, 현재 길이가 저장된다. 값까지 복사하는 것은 성능 부채가 크다 (왼쪽 테이블)
  • let s2 = s1; 에서는 s1의 Stack의 정보들이 복사되어 binding된다.
  • 문제: 만약 s1s2가 scope에서 나갈 때 drop이 동시에 발생하면 같이 참조하는 메모리를 서로 지우려할 것이다. 이 현상을 double free 에러 라고 한다.
  • 그렇기 때문에 let s2 = s1 에서는 Ownership의 이동이 발생한다. s1는 더이상 사용할 수 없다.

만약 정말 같은 값을 가졌지만 다른 Ownership을 가진 변수를 복제하고 싶은 경우에는 x.clone()을 이용한다.

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();

    println!("s1 = {}, s2 = {}", s1, s2);
}

마지막으로, 다음의 경우는 왜 move가 발생하지 않을까?

fn main() {
    let x = 5;
    let y = x;

    println!("x = {}, y = {}", x, y);
}
  • 컴파일 시에 메모리에 얼마나 할당될지 알 수 있는 정수 값은 오로지 Stack에 모두 저장될 수 있기 때문이다.
  • Rust에는 type에 Copy라는 플래그를 부여할 수 있는데, 이게 존재하는 type에 한해 move대신 복사가 일어나고, 이전에 선언했던 변수를 그대로 사용 가능하다.

함수와 Ownership

아래 처럼 인자로 받을 때도 선언하는 것과 같아서 mut을 붙일 수 있음

fn fill_vec(mut vec: Vec<i32>) -> Vec<i32> {
    vec.push(22);
    vec.push(44);
    vec.push(66);

    vec
}
  • 함수로 넘어갈 때도 Ownership의 move, copy가 발생한다.
  • 함수에서 반환할 때도 Ownership의 move가 발생한다.

Referred in

Rust - move_semantics